home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.mactech.com 2010
/
ftp.mactech.com.tar
/
ftp.mactech.com
/
machack
/
Hacks95
/
Closure.sit
/
Closure
/
Sources
/
GX Graphics Libraries
/
layout library.c
< prev
next >
Wrap
Text File
|
1995-06-24
|
16KB
|
510 lines
/* layout library.c -- Line Layout library routines.
CHANGE LOG
Date Person Action
---- ------ ------
900517 ERM • Created.
900702 ERM • Converted to new graphics-like interface.
900703 ERM • Add LineOptions parameter to SingleLayout guys.
900712 DGO • Fixed NewEasyLayout, which wasn't correctly doing LineOptions.
900731 DGO • Changed "line" to "lineOpts" throughout.
• Added code to initialize controls in SetLayoutStyle if passed-in
parameter "layoutControls" is nil.
900803 ERM • Removed controls initialization from NewSingleLayout.
• Various other formatting clean-up.
900826 DGO • Added first cut at the paragraph functions.
900828 DGO • Fixed sense-of-sign bug. *BLUSH*
900912 ERM • Bagged references to hard-coded layout feature levels.
900914 ERM • Added GetStyleLayoutFeatureNames.
900917 ERM • THINK C 3.0 compatability changes.
910114 DGO • Removed overhangRect references.
910410 DGO • Merged Mike's changes to font manager.
• Added lineHeight parameter to NewParagraph.
910415 ERM + DGO • Added include of ToolUtils.
910516 OWS • Converted to ANSI-style function declarations.
• Updated includes for Think C 5.0.
910529 DGO • Changed to final 1.0 form.
910626 DGO • Bug fixing in NewParagraph (undisposed shape, bad pointer).
910820 DGO • Added NewDiscontiguousSelection function.
• Minor name changes.
911118 ERM • Replaced GetStyleRunFeatureNames w/ GetStyleRunFeatureTypeNames, GetStyleRunFeatureSelectorNames.
911120 ERM • Removed gxRunFeatureType from RunFeatureSelectorName.
911124 DGO • Moved NewDiscontiguousSelection to selection library.
920309 ERM • GXNewLayout now has explicit run counts.
920505 DGO • Fixed NewStyledParagraph linebreaking bug.
930623 DGO • Added GXIgnoreGraphicsNotice for text_attributes_already_set.
*/
/* Copyright ©1990-1993 Apple Computer, Inc. All rights reserved. */
#ifndef powerc
#pragma pointers_in_D0
#endif
#include <Types.h>
#include <Memory.h>
#include <Resources.h>
#include <ToolUtils.h>
#include "graphics toolbox.h"
#include "graphics routines.h"
#include "math routines.h"
#include "layout types.h"
#include "layout routines.h"
#include "font routines.h"
#ifndef powerc
#pragma pointers_in_A0
#endif
#include "layout library.h"
#include "font library.h"
void InitializeLayoutOptions (gxLayoutOptions *layoutOptions)
{ layoutOptions->width = 0;
layoutOptions->flush = 0;
layoutOptions->just = 0;
layoutOptions->flags = 0;
layoutOptions->baselineRec = nil;
}
void SetDefaultPriorityJustOverride (gxPriorityJustificationOverride *override)
{ short i;
gxWidthDeltaRecord *pDelta;
pDelta = override->deltas;
for (i = 0; i < gxNumberOfJustificationPriorities; i++)
{ pDelta->growFlags = pDelta->shrinkFlags = 0;
pDelta->beforeGrowLimit = pDelta->afterGrowLimit =
pDelta->beforeShrinkLimit = pDelta->afterShrinkLimit = 0;
pDelta++;
} /* endloop i */
}
void InitializeRunControls (gxRunControls *runControls)
{ runControls->flags = 0;
runControls->beforeWithStreamShift = runControls->afterWithStreamShift = 0;
runControls->crossStreamShift = 0;
runControls->imposedWidth = 0;
runControls->track = 0;
runControls->hangingInhibitFactor = runControls->kerningInhibitFactor = 0;
runControls->baselineType = gxRomanBaseline;
runControls->decompositionAdjustmentFactor = 0;
}
void InitializeStyleRunOverrides (StyleRunOverrides *overrides)
{ overrides->priorityJustOverride = nil;
overrides->glyphJustOverrides = nil;
overrides->glyphJustOverridesCount = 0;
overrides->glyphSubstitutions = nil;
overrides->glyphSubstitutionsCount = 0;
overrides->kerningAdjustments = nil;
overrides->kerningAdjustmentsCount = 0;
}
static void SetStyleNamedFont(gxStyle s, unsigned char* name)
{
// gxFont fontID = FindPNameFont(gxFullFontName, name);
gxFont fontID = FindPNameFont(gxFamilyFontName, name);
if (fontID != GXGetStyleFont(s))
GXSetStyleFont(s, fontID);
}
void SetLayoutStyle (
gxStyle s,
long txFont, long txFace,
Fixed textSize,
gxTextAttribute attr,
gxRunControls *runControls,
gxRunFeature runFeatures[],
long runFeaturesCount,
StyleRunOverrides *overrides)
{ gxRunControls localControls;
#ifdef debugging
GXIgnoreGraphicsNotice(attributes_already_set);
GXIgnoreGraphicsNotice(text_attributes_already_set);
#endif
(void)GXConvertQDFont(s, txFont, txFace);
//SetStyleNamedFont (s, (unsigned char*)gxFontName);
GXSetStyleTextSize (s, textSize);
GXSetStyleTextAttributes (s, attr);
if (!runControls)
{ InitializeRunControls(&localControls);
runControls = &localControls;
}
GXSetStyleRunControls (s, runControls);
if (runFeatures) GXSetStyleRunFeatures (s, runFeaturesCount, runFeatures);
if (overrides)
{ if (overrides->glyphSubstitutions)
GXSetStyleRunGlyphSubstitutions (s, overrides->glyphSubstitutionsCount, overrides->glyphSubstitutions);
if (overrides->kerningAdjustments)
GXSetStyleRunKerningAdjustments (s, overrides->kerningAdjustmentsCount, overrides->kerningAdjustments);
if (overrides->glyphJustOverrides)
GXSetStyleRunGlyphJustOverrides (s, overrides->glyphJustOverridesCount, overrides->glyphJustOverrides);
if (overrides->priorityJustOverride)
GXSetStyleRunPriorityJustOverride (s, overrides->priorityJustOverride);
}
#ifdef debugging
GXPopGraphicsNotice();
GXPopGraphicsNotice();
#endif
}
gxStyle NewLayoutStyle (
long txFont, long txFace,
Fixed textSize,
gxTextAttribute attr,
gxRunControls *runControls,
gxRunFeature runFeatures[],
long runFeaturesCount,
StyleRunOverrides *overrides)
{ gxStyle newStyle = GXNewStyle ();
SetLayoutStyle (
newStyle,
txFont, txFace,
textSize,
attr,
runControls,
runFeatures,
runFeaturesCount,
overrides);
return (newStyle);
}
#if 0
gxShape NewSingleLayout (
char *text,
char *gxFontName,
Fixed textSize,
gxLayoutOptions *options,
gxPoint *position,
gxTextAttribute attr,
gxRunControls *runControls,
gxRunFeature runFeatures[],
long runFeaturesCount,
StyleRunOverrides *overrides)
{ gxStyle newLayoutStyle;
gxShape newLayoutShape;
short len, level = 0;
char *s;
newLayoutStyle = NewLayoutStyle (
gxFontName,
textSize,
attr,
runControls,
runFeatures,
runFeaturesCount,
overrides);
for (len = 0, s = text; *s++ != 0; len++) ;
newLayoutShape = GXNewLayout (
1,
&len,
(const void **) &text,
1,
&len,
&newLayoutStyle,
1,
&len,
&level,
options,
position);
GXDisposeStyle (newLayoutStyle);
return newLayoutShape;
}
#endif
/* NewParagraph is the simplest of the paragraph creation functions. It assumes a single
gxStyle for the whole paragraph, and does its own deduction about where the paragraph
ends (namely at a hard stop, CR or HT). */
short CountBytes(char *text);
short CountBytes(char *text)
{
short count = 0;
while (*text != 13 && *text != 9)
{text++; count++;}
return count;
} /* CountBytes */
ParagraphRecordHandle NewParagraph(
char *text,
gxStyle baseStyle,
Fixed width,
long justified,
Fixed lineHeight,
gxPoint *firstOrigin)
{
/* Constants */
#define extraLineGap ff(2)
#define lineStartsCount 50
/* Variables */
boolean startIsStaked;
gxByteOffset lineStarts[lineStartsCount], newLineStart, nextStake,
nls2, priorStake, thisLineStart;
char *pChar;
Fixed currLineDelta, textSize;
gxLayoutOptions options;
ParagraphRecordHandle paraHandle;
gxShape bigLayout, thisLine;
short byteCount, i, level = 0, nextLineIndex;
byteCount = CountBytes(text); /* doesn't count the CR or HT!! */
bigLayout = GXNewLayout(
1,
&byteCount,
(const void **) &text,
1,
&byteCount,
&baseStyle,
1,
&byteCount,
&level,
nil,
firstOrigin);
/* We next compute the gxLine breaks and store the offsets that correspond to them in a
temporary array. */
thisLineStart = 0;
nextLineIndex = 0;
while (thisLineStart < byteCount && nextLineIndex < lineStartsCount - 1)
{
lineStarts[nextLineIndex++] = thisLineStart;
newLineStart = GXGetLayoutBreakOffset(
bigLayout, thisLineStart, width, 0, nil, &startIsStaked, &priorStake, &nextStake);
if (newLineStart == byteCount) break;
/* Now backtrack to first prior space. */
nls2 = newLineStart;
pChar = text + newLineStart - 1;
while (nls2 >= 0 && *pChar != ' ')
{
pChar--;
nls2--;
}
if (nls2 < 0) thisLineStart = newLineStart;
else thisLineStart = nls2;
}
lineStarts[nextLineIndex] = byteCount;
/* Allocate space for the ParagraphRecord. */
paraHandle = (ParagraphRecordHandle) NewHandle(
(Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
(*paraHandle)->nLayouts = nextLineIndex;
/* Now create the layouts and place them in the ParagraphRecord. */
InitializeLayoutOptions(&options);
options.width = width;
if (justified) options.just = fract1;
textSize = GXGetStyleTextSize(baseStyle);
currLineDelta = 0;
for (i = 0; i < nextLineIndex; i++)
{
if (i == nextLineIndex - 1) options.just = 0; /* don't justify the last gxLine... */
thisLine = GXNewLayoutFromRange(
bigLayout, lineStarts[i], lineStarts[i+1], &options, nil);
if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
(*paraHandle)->layouts[i] = thisLine;
currLineDelta += (lineHeight ? lineHeight : (textSize + extraLineGap));
}
(*paraHandle)->totalHeight = currLineDelta;
GXDisposeShape(bigLayout);
return paraHandle;
} /* NewParagraph */
static char *GetTextPiecePtr(
const void *text[],
const short textRunLengths[],
short offset)
{
char **pPiece = (char **) text;
short oCopy = offset;
short *runLength = (short *) textRunLengths;
while (oCopy > *runLength)
{oCopy -= *runLength++; pPiece++;}
return *pPiece + oCopy;
} /* GetTextPiecePtr */
static long GetPreviousOffset(gxShape layout, long offset)
{ unsigned short firstGlyph, secondGlyph;
gxLayoutOffsetState offsetState;
static long offsetStateSizes[] = {1, 1, 2, 2, 0};
GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
}
static long GetNextOffset(gxShape layout, long offset)
{ unsigned short firstGlyph, secondGlyph;
gxLayoutOffsetState offsetState;
static long offsetStateSizes[] = {1, 2, 1, 2, 0};
GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
return offset + offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
}
ParagraphRecordHandle NewStyledParagraph(
long textRunCount,
const void *text[],
const short textRunLengths[],
long styleRunCount,
const gxStyle styles[],
const short styleRunLengths[],
long levelRunCount,
const short levels[],
const short levelRunLengths[],
long totalByteCount,
const gxLayoutOptions *layoutOptions,
Fixed lineHeight,
const gxPoint *firstOrigin)
{
/* Variables */
boolean startIsStaked;
gxByteOffset lineStarts[lineStartsCount], newLineStart, nextStake,
nls2, priorStake, thisLineStart;
char *pChar, *pSav;
Fixed currLineDelta, lineAscent, lineDescent;
gxLayoutOptions specialOptions;
ParagraphRecordHandle paraHandle;
gxShape bigLayout, thisLine;
short i, level = 0, nextLineIndex;
specialOptions = *layoutOptions;
specialOptions.just = specialOptions.flush = 0;
specialOptions.width = 0;
bigLayout = GXNewLayout(
textRunCount,
textRunLengths,
text,
styleRunCount,
styleRunLengths,
styles,
levelRunCount,
levelRunLengths,
levels,
&specialOptions,
firstOrigin);
/* We next compute the gxLine breaks and store the offsets that correspond to them in a
temporary array. */
thisLineStart = 0;
nextLineIndex = 0;
while (thisLineStart < totalByteCount && nextLineIndex < lineStartsCount - 1)
{
lineStarts[nextLineIndex++] = thisLineStart;
newLineStart = GXGetLayoutBreakOffset(
bigLayout,
thisLineStart,
layoutOptions->width,
0,
nil,
&startIsStaked,
&priorStake,
&nextStake);
if (newLineStart == totalByteCount) break;
/* Now backtrack to first prior space. */
nls2 = newLineStart;
pSav = pChar = GetTextPiecePtr(text, textRunLengths, GetPreviousOffset(bigLayout, newLineStart));
while (nls2 >= lineStarts[nextLineIndex-1] && *pChar != ' ')
pChar = GetTextPiecePtr(text, textRunLengths, nls2 = GetPreviousOffset(bigLayout, nls2));
if (nls2 <= lineStarts[nextLineIndex-1]) thisLineStart = newLineStart;
else
{
if (pSav != pChar) nls2 = GetNextOffset(bigLayout, nls2);
thisLineStart = nls2;
}
}
lineStarts[nextLineIndex] = (short) totalByteCount;
/* Allocate space for the ParagraphRecord. */
paraHandle = (ParagraphRecordHandle) NewHandle(
(Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
(*paraHandle)->nLayouts = nextLineIndex;
/* Now create the layouts and place them in the ParagraphRecord. */
specialOptions = *layoutOptions;
currLineDelta = 0;
for (i = 0; i < nextLineIndex; i++)
{
if (i == nextLineIndex - 1) specialOptions.just = 0; /* don't justify last gxLine... */
thisLine = GXNewLayoutFromRange(
bigLayout, lineStarts[i], lineStarts[i+1], &specialOptions, nil);
if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
(*paraHandle)->layouts[i] = thisLine;
if (lineHeight) currLineDelta += lineHeight;
else
{
GXGetLayoutSpan(thisLine, &lineAscent, &lineDescent);
currLineDelta += lineAscent + lineDescent + extraLineGap;
}
}
(*paraHandle)->totalHeight = currLineDelta;
GXDisposeShape(bigLayout);
return paraHandle;
} /* NewStyledParagraph */
/* DisposeParagraph disposes of the memory associated with a paragraph. While currently
simple, it could be more involved if the paragraph itself retains more information. */
void DisposeParagraph(ParagraphRecordHandle paraRec)
{
short i;
for (i = 0; i < (*paraRec)->nLayouts; i++)
GXDisposeShape((*paraRec)->layouts[i]);
DisposeHandle((Handle) paraRec);
} /* DisposeParagraph */
/* GetLayoutBounds returns a gxShape corresponding to the bounds of the specified layout. It
differs from GXGetShapeBounds in two respects: first, it returns a gxShape (rather than just
a gxRectangle); and second, it takes both the layout's position and its gxMapping into account
(GXGetShapeBounds only takes the layout's position into account). */
gxShape GetLayoutBounds(gxShape layout)
{
gxMapping thisMapping;
gxRectangle thisRect;
gxShape rectShape;
GXGetShapeBounds(layout, 0, &thisRect);
rectShape = GXNewRectangle(&thisRect);
#if 0
GXIgnoreGraphicsNotice(transform_already_set);
GXSetShapeTransform(rectShape, GXGetShapeTransform(layout));
GXPopGraphicsNotice();
#else
GXMapShape(rectShape, GXGetTransformMapping(GXGetShapeTransform(layout), &thisMapping));
#endif
return rectShape;
} /* GetLayoutBounds */